<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id='code'>
    </div>
    <script id='template-head' type="text/template">
        <h3 on-click={this.handlerClick}><span>sssss</span>{this.state.value}</h3>
    </script>



    <script src="template.js"></script>
    <script>

        (function (context) {

            //带构造函数的对象继承
            var Extend = function (Parent, Child) {
                var F = function () { }; //声明一个空类
                F.prototype = Parent.prototype; //这个类的 prototype 指向 父类的 prototype
                Child.prototype = new F(); //创建空类的对象，并将空类对象赋值给 子类的 prototype
                Child.prototype.constructor = Child; //将子类的构造函数改回自身的构造函数（指向父类的 ptotitype 的时候，被改为父类的构造函数了）
                Child.uper = Parent.prototype; //添加一个指向父类的属性
                return Child;
            }
            //基础组件
            var BaseComponent = function (props) {
                //容器
                this.container = document.createElement("div");
                if (typeof props == "undefined") props = {};
                this.props = props;
                this.state = {};
                this.element = null;
                this.componentchildren = [];
                this.updateHandler = [];//事件列表


                if (typeof BaseComponent._inited_ == "undefined") {
                    //更新组件
                    BaseComponent.prototype.update = function (props) {

                        if (this.updateHandler.length > 0) {
                            for (var fnkey in this.updateHandler) {
                                var fn = this.updateHandler[fnkey].bind(this);
                                fn(this);
                            }
                        }
                    }
                    //更新组件
                    BaseComponent.prototype.componentUpdate = function (props) {
                        if (typeof props == "undefined") props = {};
                        this.props = props;
                        this.update();
                    }
                    //初始化后执行
                    BaseComponent.prototype.componentDidMount = function () {

                    }
                    //被卸载时执行
                    //TODO 暂时不懂该在什么地方执行，预留着
                    BaseComponent.prototype.componentWillUnmount = function () {

                    }
                    //返回 html
                    BaseComponent.prototype.render = function () {

                    }
                    //更新 state
                    BaseComponent.prototype.setState = function (state) {

                        //是 function 的话作为回调使用
                        if (typeof state === "function") {
                            state = state(this.state)
                        }

                        if (typeof state === "object") {
                            for (var key in state) {
                                this.state[key] = state[key];
                            }
                        }
                        //更新 element
                        this.update();
                        //var tempnode = this.getElement();

                        //this.element.parentNode.replaceChild(tempnode, this.element);
                        // this.element = tempnode;
                    }

                    //创建子组件
                    BaseComponent.prototype.createComponent = function (comname, props) {
                        var func = new Function("props", "return new " + comname + "(props)");
                        var component = func(props);
                        return component;
                    }

                    BaseComponent.prototype.handlerChild = function (children) {
                        for (var index = 0; index < children.length; index++) {
                            var node = children[index];
                            //普通内容节点，解析内容处理
                            if (node.nodeName == '#text' && node.nodeValue.length > 0) {

                                var func = JSTemplate.getFunc(node.nodeValue)
                                var nodevalue = func.call(this, this, this.props);
                                node.nodeValue = nodevalue;


                                var updatefn = function (name, func, node) {
                                    return function (comobj) {
                                        var _this = comobj;
                                        var _name = name;
                                        var _func = func;
                                        var _node = node;
                                        var nodevalue = _func.call(_this, _this, _this.props);
                                        _node.nodeValue = nodevalue;
                                    }
                                }
                                updatefn = updatefn.bind(this);
                                var fn = updatefn(name, func, node).bind(this);
                                fn(this);
                                this.updateHandler.push(fn);
                            }
                            //用户组件处理
                            else if (node.nodeName == 'COMPONENT') {

                                var comname = "";
                                var comprops = {};
                                //是判断是否有包含内容，有的话，将内容转成 dom 之后再返回 children，然后这个children 将作为一个参数传递到 这个组件，至于这个组将要将子内容放到哪里，那是另外一回事
                                if (node.childNodes.length > 0) {
                                    var comchildren = this.handlerChild(node.childNodes);
                                    //这里能做么做comchildren[0] 前提是 这个 componentchildren 标签没有兄弟标签,即 如果要给 组件加上 children 的话，最外层必须是一个大标签
                                    comprops["component-children"] = comchildren[0];
                                }

                                var compropsfns = [];


                                var attrnames = node.getAttributeNames();
                                for (var key in attrnames) {
                                    var name = attrnames[key];
                                    //除了组件名称，其余的均当作对象的值来处理

                                    var value = node.getAttribute(name);
                                    // 指定 com-name 属性的值为组件 名称
                                    if (name === 'com-name') {
                                        comname = value;
                                    }
                                    else {
                                        var func = JSTemplate.getFunc(value)

                                        var nodevalue = func.call(this, this, this.props);
                                        comprops[name] = nodevalue;

                                        //保存获取 props 的方法
                                        var updatefn = function (name,func) {

                                            return function (comobj) {
                                                var _this = comobj;
                                                var _name = name;
                                                var _fun = func;
                                                var nodevalue = func.call(_this, _this, _this.props);
                                                return {name:name,value:nodevalue}
                                            }
                                        }
                                        updatefn = updatefn.bind(this);
                                        var fn = updatefn(name,func).bind(this);
                                        compropsfns.push(fn);

                                    }
                                }

                                //创建并替换子节点
                                var com = this.createComponent(comname, comprops);
                                node.parentNode.replaceChild(com.handerRender(), node);
                                this.componentchildren.push(com);

                                var updatefn = function (com,compropsfns) {

                                    return function (comobj) {
                                        var _this = comobj;
                                        var _com = com;
                                        var _compropsfns = compropsfns;
                                        
                                        var _props ={};
                                        if(_compropsfns.length>0)
                                        {
                                            for(var _index=0;_index<compropsfns.length;_index++)
                                            {
                                                var compropsinfo= compropsfns[_index](this);
                                                _props[compropsinfo.name] = compropsinfo.value;
                                            }
                                        }

                                        _com.componentUpdate(_props);//子组件只需要操作更新
                                    }
                                }
                                updatefn = updatefn.bind(this);
                                var fn = updatefn(com,compropsfns).bind(this);
                                //fn(this);
                                this.updateHandler.push(fn);


                            }
                            //如果是子内容（我们规定 使用 CHILDREN 作为节点名称的，将会被传进来的  component-children 覆盖）
                            else if (node.nodeName == 'CHILDREN') {
                                var componentchildren = this.props["component-children"];
                                if (typeof componentchildren === 'object') {
                                    //这里能做么做 前提是 这个 componentchildren 标签没有兄弟标签,即 如果要给 组件加上 children 的话，最外层必须是一个大标签
                                    node.parentNode.replaceChild(componentchildren, node);
                                }
                                else
                                    node.remove();
                            }
                            //非 组件 dom 节点解析
                            else {
                                var attrnames = node.getAttributeNames();
                                for (var key in attrnames) {
                                    var name = attrnames[key];
                                    //是 on- 开头说明是事件，需要做处理
                                    if (name.indexOf("on-") > -1) {
                                        var attrvalue = node.getAttribute(name);
                                        //TODO添加事件监听
                                        /*
                                            将 this.去掉，然后根据值的层次，一层一层的往下取目标 事件处理方法
                                        */
                                        attrvalue = attrvalue.replace("this.", "").replace("{", "").replace("}", "");
                                        var func = this;
                                        var fninfo = attrvalue.split('.')
                                        for (var fnkey in fninfo) {
                                            var fnname = fninfo[fnkey];
                                            var func = func[fnname];
                                        }
                                        if (typeof func == 'function') node.addEventListener(name.replace("on-", ""), func)

                                        node.removeAttribute(name)
                                    }
                                    //非 事件 的属性，只需要解析赋值既可以
                                    else {

                                        var attrvalue = node.getAttribute(name);
                                        if (attrvalue.length > 0) {
                                            var func = JSTemplate.getFunc(attrvalue)

                                            var updatefn = function (name, func, node) {
                                                return function (comobj) {
                                                    var _this = comobj;
                                                    var _name = name;
                                                    var _func = func;
                                                    var _node = node;

                                                    var _attrvalue = func.call(_this, _this, _this.props);
                                                    _node.removeAttribute(_name);
                                                    _node.setAttribute(_name, _attrvalue);
                                                }
                                            }
                                            updatefn = updatefn.bind(this);
                                            var fn = updatefn(name, func, node).bind(this);
                                            fn(this);
                                            this.updateHandler.push(fn);

                                        }
                                    }
                                }
                            }
                            if (node.childNodes.length > 0) {
                                node.childNodes = this.handlerChild(node.childNodes)
                            }
                        }
                        return children;
                    }

                    //渲染（返回dom）
                    BaseComponent.prototype.getElement = function () {

                        var templatecontent = this.render();
                        //var func = JSTemplate.getFunc(templatecontent)
                        //var html = func.call(this, this, props);
                        /*
                            将 html 放到一个 dom 容器中，然后再解析里面的事件标识
                        */
                        this.container.innerHTML = templatecontent;

                        this.container.childNodes = this.handlerChild(this.container.childNodes)
                        var child = this.container.children[0];

                        return child;
                    }

                    //渲染（返回dom）
                    BaseComponent.prototype.handerRender = function () {
                        this.element = this.getElement();
                        //初始化完成回调
                        this.componentDidMount();
                        return this.element;
                    }
                    BaseComponent._inited_ = true;
                }
            }

            //根 组件，用于渲染入口，默认不需要传值（作为根组件，也没有必要传值，如果是需要传值的组件，则再包装一层组件即可，）
            //直接传入根组件 的 html 写法
            var RootComponent = Extend(BaseComponent, function (rootComponentHtml) {
                BaseComponent.call(this, {});
                if (typeof RootComponent._inited_ == "undefined") {

                    //覆盖获取模板内容的方法
                    RootComponent.prototype.render = function () {
                        return rootComponentHtml;
                    }
                    RootComponent._inited_ = true;
                }

            }); //继承 基础组件

            var DOMRender = function (rootComponentHtml, rootnode) {
                var component = new RootComponent(rootComponentHtml);
                var html = component.handerRender();
                rootnode.appendChild(html);
            }

            //对外开放
            context.MyReact = {
                Extend: Extend,
                BaseComponent: BaseComponent,
                DOMRender: DOMRender
            }

        })(window)


        var Item = MyReact.Extend(MyReact.BaseComponent, function (props) {
            MyReact.BaseComponent.call(this, props);

            if (typeof Item._inited_ == "undefined") {
                //覆盖获取模板内容的方法
                Item.prototype.render = function () {
                    return "<p>{this.props.value}</p>";
                }
                Item._inited_ = true;
            }


        }); //继承 基础组件



        var MyForm = MyReact.Extend(MyReact.BaseComponent, function (props) {
            MyReact.BaseComponent.call(this, props);

            this.state = { value: new Date() };

            if (typeof MyForm._inited_ == "undefined") {

                //初始化后执行
                MyForm.prototype.componentDidMount = function () {
                    //this.TimerId = setInterval(this.updateState, 1000);
                }
                //TODO 暂时不懂该在什么地方执行，预留着
                MyForm.prototype.componentWillUnmount = function () {
                    //clearInterval(this.TimerId);
                }

                //
                MyForm.prototype.updateState = function () {
                    this.setState({ value: new Date() })
                }
                //覆盖获取模板内容的方法
                MyForm.prototype.render = function () {
                    return "<div><input value={this.state.value.toLocaleTimeString()} />:<span on-click={this.updateState}>{this.state.value}</span><component com-name=Item value={this.state.value} ></component></div>";
                }
                MyForm._inited_ = true;
            }

            this.updateState = this.updateState.bind(this);


        }); //继承 基础组件



        MyReact.DOMRender("<component com-name=MyForm ></component>", document.getElementById("code"))


    </script>
</body>

</html>